package org.testile.datasetgenerifier;

import com.google.common.base.Function;
import groovy.util.BuilderSupport;
import java.util.Collections;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testile.datasetgenerifier.impl.DefaultColumnGenerifier;
import org.testile.datasetgenerifier.impl.DefaultDatasetGenerifier;
import org.testile.datasetgenerifier.impl.DefaultTableGenerifier;

/**
 *
 * @author ytoh
 */
public class DataSetGenerifierBuilder extends BuilderSupport {

	private static final Logger logger = LoggerFactory.getLogger(DataSetGenerifierBuilder.class);
	private Map<String, TransformationFactory> transformationFactories;
	private DefaultDatasetGenerifier datasetGenerifier;
	private String currentTable;
	private String currentColumn;

	private DataSetGenerifierBuilder(Map<String, TransformationFactory> transformations) {
		this.transformationFactories = transformations;
	}

	public static DataSetGenerifierBuilder with(Map<String, TransformationFactory> transformations) {
		DataSetGenerifierBuilder builder = new DataSetGenerifierBuilder(transformations);
		return builder;
	}

	@Override
	protected void setParent(Object parent, Object child) {
		logger.debug("setParent(parent:{}, child:{})", parent, child);
	}

	@Override
	protected Object createNode(Object name) {
		logger.debug("createNode(name:{})", name);

		if("generify".equals(name)) {
			return createDatasetGenerifier();
		}

		return registerTransformation((String) name, null, Collections.emptyMap());
	}

	private DefaultDatasetGenerifier createDatasetGenerifier() {
		datasetGenerifier = new DefaultDatasetGenerifier();
		return datasetGenerifier;
	}

	public DefaultDatasetGenerifier getDatasetGenerifier() {
		return datasetGenerifier;
	}

	@Override
	protected Object createNode(Object name, Object value) {
		logger.debug("createNode(name:{}, value:{})", name, value);

		if("table".equals(name)) {
			currentTable = (String) value;
			return createTableGenerifier((String) value);
		}

		if("column".equals(name)) {
			currentColumn = (String) value;
			return createColumnGenerifier((String) value);
		}

		return registerTransformation((String)name, value, Collections.emptyMap());
	}

	private DefaultTableGenerifier createTableGenerifier(String name) {
		DefaultTableGenerifier tableGenerifier = new DefaultTableGenerifier();
		datasetGenerifier.addTableGenerifier(name, tableGenerifier);
		return tableGenerifier;
	}

	private Object createColumnGenerifier(String name) {
		DefaultColumnGenerifier columnGenerifier = new DefaultColumnGenerifier();
		DefaultTableGenerifier tableGenerifier = (DefaultTableGenerifier) datasetGenerifier.getTableGenerifier(currentTable);
		tableGenerifier.addColumnGenerifier(name, columnGenerifier);
		return columnGenerifier;
	}

	@Override
	protected Object createNode(Object name, Map attributes) {
		logger.debug("createNode(name:{}, attributes:{})", name, attributes);
		return registerTransformation((String)name, null, attributes);
	}

	@Override
	protected Object createNode(Object name, Map attributes, Object value) {
		logger.debug("createNode(name:{}, attributes:{}, value:{})", new Object[] {name, attributes, value});
		return registerTransformation((String)name, value, attributes);
	}

	@Override
	protected void nodeCompleted(Object parent, Object node) {
		logger.debug("nodeCompleted(parent:{}, node:{})", parent, node);
	}

	private Function<String,String> registerTransformation(String name, Object value, Map attributes) {
		logger.debug("registerTransformation(name:{}, value:{}, attributes:{})", new Object[] {name, value, attributes});

		TransformationFactory factory = transformationFactories.get(name);

		if (factory == null) {
			logger.warn("No transformation for name '{}'. No transformation registered.", name);
			
			return null;
		} else {
			Function<String, String> transformation = factory.newInstance(value, attributes);
			DefaultColumnGenerifier columnGenerifier = (DefaultColumnGenerifier)datasetGenerifier.getTableGenerifier(currentTable).getColumnGenerifier(currentColumn);
			columnGenerifier.addTransformation(transformation);

			return transformation;
		}
	}
}
